format ELF64 executable 3
entry Main

RTLD_LAZY = 1

SDL_KEYDOWN = 2
SDL_INIT_VIDEO = 0x00000020
SDL_OPENGL = 0x00000002
SDL_NOFRAME = 0x00000020
SDL_GL_RED_SIZE = 0
SDL_GL_GREEN_SIZE = 1
SDL_GL_BLUE_SIZE = 2
SDL_GL_DOUBLEBUFFER = 5
SDL_GL_DEPTH_SIZE = 6
SDL_GL_STENCIL_SIZE = 7

GL_COLOR_BUFFER_BIT = 0x00004000
GL_STENCIL_BUFFER_BIT = 0x00000400
GL_VERTEX_PROGRAM_ARB = 0x8620
GL_FRAGMENT_PROGRAM_ARB = 0x8804
GL_PROGRAM_FORMAT_ASCII_ARB = 0x8875
GL_STATIC_DRAW = 0x88E4
GL_BUFFER_GPU_ADDRESS_NV = 0x8F1D
GL_READ_ONLY = 0x88B8
GL_VERTEX_ATTRIB_ARRAY_UNIFIED_NV = 0x8F1E
GL_VERTEX_ATTRIB_ARRAY_ADDRESS_NV = 0x8F20
GL_FALSE = 0
GL_TRUE = 1
GL_ZERO = 0
GL_TRIANGLES = 0x0004
GL_FLOAT = 0x1406
GL_STENCIL_TEST = 0x0B90
GL_DEPTH_TEST = 0x0B71
GL_NOTEQUAL = 0x0205
GL_KEEP = 0x1E00
GL_COUNT_UP_NV = 0x9088
GL_BOUNDING_BOX_NV = 0x908D
GL_CLOSE_PATH_NV = 0x00
GL_MOVE_TO_NV = 0x02
GL_RELATIVE_MOVE_TO_NV = 0x03
GL_LINE_TO_NV = 0x04

include     'import64.inc'
interpreter '/lib64/ld-linux-x86-64.so.2'
needed      'libdl.so.2'
import      dlopen,dlsym

;-------------------------------------------------------------------------------
; NAME:     ldsdlf
; DESC:     Load SDL function.
;-------------------------------------------------------------------------------
macro       ldsdlf      name* {
            mov         rdi,[g_libSDL]
            mov         rsi,g_str_#name
            call        [dlsym]
            mov         [name],rax
}
;-------------------------------------------------------------------------------
; NAME:     ldglf
; DESC:     Load OpenGL function.
;-------------------------------------------------------------------------------
macro       ldglf       name* {
            mov         rdi,g_str_#name
            call        [SDL_GL_GetProcAddress]
            mov         [name],rax
}
;-------------------------------------------------------------------------------
; NAME:     stglattr
; DESC:     Set OpenGL attribute.
;-------------------------------------------------------------------------------
macro       stglattr    param*, value* {
            mov         edi,param
            mov         esi,value
            call        [SDL_GL_SetAttribute]
}

segment readable executable

;-------------------------------------------------------------------------------
; NAME:     LoadFunctions
;-------------------------------------------------------------------------------
LoadFunctions:
            sub         rsp,8
            ; load SDL 1.2 library
            mov         rdi,g_str_libSDL
            mov         esi,RTLD_LAZY
            call        [dlopen]
            mov         [g_libSDL],rax
            ; load SDL functions
            ldsdlf      SDL_Init
            ldsdlf      SDL_Quit
            ldsdlf      SDL_SetVideoMode
            ldsdlf      SDL_PollEvent
            ldsdlf      SDL_GetTicks
            ldsdlf      SDL_GL_SwapBuffers
            ldsdlf      SDL_GL_GetProcAddress
            ldsdlf      SDL_GL_SetAttribute
            ldsdlf      SDL_GL_LoadLibrary
            add         rsp,8
            ret
;-------------------------------------------------------------------------------
; NAME:     OpenWindow
;-------------------------------------------------------------------------------
OpenWindow:
            sub         rsp,8
            ; call SDL_Init
            mov         edi,SDL_INIT_VIDEO
            call        [SDL_Init]
            ; set OpenGL attributes
            stglattr    SDL_GL_DOUBLEBUFFER,1
            stglattr    SDL_GL_RED_SIZE,8
            stglattr    SDL_GL_GREEN_SIZE,8
            stglattr    SDL_GL_BLUE_SIZE,8
            stglattr    SDL_GL_DEPTH_SIZE,24
            stglattr    SDL_GL_STENCIL_SIZE,8
            ; call SDL_GL_LoadLibrary
            xor         edi,edi
            call        [SDL_GL_LoadLibrary]
            ; call SDL_SetVideoModeprogram
            mov         edi,800
            mov         esi,800
            xor         edx,edx
            mov         ecx,SDL_OPENGL+SDL_NOFRAME
            call        [SDL_SetVideoMode]
            add         rsp,8
            ret
;-------------------------------------------------------------------------------
; NAME:     LoadOGLFunctions
;-------------------------------------------------------------------------------
LoadOGLFunctions:
            sub         rsp,8
            ldglf       glClear
            ldglf       glBindProgramARB
            ldglf       glNamedProgramStringEXT
            ldglf       glNamedBufferDataEXT
            ldglf       glGetNamedBufferParameterui64vNV
            ldglf       glMakeNamedBufferResidentNV
            ldglf       glEnable
            ldglf       glEnableClientState
            ldglf       glVertexAttribFormatNV
            ldglf       glEnableVertexAttribArray
            ldglf       glBufferAddressRangeNV
            ldglf       glDrawArrays
            ldglf       glPathCommandsNV
            ldglf       glStencilFillPathNV
            ldglf       glCoverFillPathNV
            ldglf       glStencilFunc
            ldglf       glStencilOp
            add         rsp,8
            ret
;-------------------------------------------------------------------------------
; NAME:     Init
;-------------------------------------------------------------------------------
Init:
            sub         rsp,8
            ; create fragment program object
            mov         edi,g_FP.NAME
            mov         esi,GL_FRAGMENT_PROGRAM_ARB
            mov         edx,GL_PROGRAM_FORMAT_ASCII_ARB
            mov         ecx,g_FP.SRC_SIZE
            mov         r8,g_FP.Src
            call        [glNamedProgramStringEXT]
            ; create path object
            mov         edi,g_Path.NAME
            mov         esi,g_Path.CMDS_COUNT
            mov         rdx,g_Path.Cmds
            mov         ecx,g_Path.COORDS_COUNT
            mov         r8d,g_Path.COORDS_TYPE
            mov         r9,g_Path.Coords
            call        [glPathCommandsNV]
            add         rsp,8
            ret
;-------------------------------------------------------------------------------
; NAME:     Update
;-------------------------------------------------------------------------------
Update:
            sub         rsp,8
            ; clear buffers
            mov         edi,GL_COLOR_BUFFER_BIT+GL_STENCIL_BUFFER_BIT
            call        [glClear]
            ; enable and bind fragment program
            mov         edi,GL_FRAGMENT_PROGRAM_ARB
            call        [glEnable]
            mov         edi,GL_FRAGMENT_PROGRAM_ARB
            mov         esi,g_FP.NAME
            call        [glBindProgramARB]
            ; stencil the path
            mov         edi,g_Path.NAME
            mov         esi,GL_COUNT_UP_NV
            mov         edx,0x1f
            call        [glStencilFillPathNV]
            ; cover the path
            mov         edi,GL_STENCIL_TEST
            call        [glEnable]
            mov         edi,GL_NOTEQUAL
            mov         esi,0
            mov         edx,0x1f
            call        [glStencilFunc]
            mov         edi,GL_KEEP
            mov         esi,GL_KEEP
            mov         edx,GL_ZERO
            call        [glStencilOp]
            mov         edi,g_Path.NAME
            mov         esi,GL_BOUNDING_BOX_NV
            call        [glCoverFillPathNV]
            add         rsp,8
            ret
;-------------------------------------------------------------------------------
; NAME:     RunMainLoop
;-------------------------------------------------------------------------------
RunMainLoop:
            Event       equ rbp-64
            push        rbp
            mov         rbp,rsp
            sub         rsp,64
.MainLoop:
            ; process window events
            lea         rdi,[Event]
            call        [SDL_PollEvent]
            cmp         byte [Event],SDL_KEYDOWN
            je          .MainLoopEnd
            ; draw and update
            call        Update
            ; swap
            call        [SDL_GL_SwapBuffers]
            jmp         .MainLoop
.MainLoopEnd:
            mov         rsp,rbp
            pop         rbp
            ret
            restore     Event
;-------------------------------------------------------------------------------
; NAME: Main
; DESC: Program entry point.
;-------------------------------------------------------------------------------
Main:
            call        LoadFunctions
            call        OpenWindow
            call        LoadOGLFunctions
            call        Init
            call        RunMainLoop
            call        [SDL_Quit]
            ; terminate process
            mov         eax,60
            xor         edi,edi
            syscall

segment readable writeable

align 8

g_libSDL dq 0

SDL_Init            dq 0
SDL_Quit            dq 0
SDL_SetVideoMode    dq 0
SDL_PollEvent       dq 0
SDL_GetTicks        dq 0

SDL_GL_LoadLibrary      dq 0
SDL_GL_GetProcAddress   dq 0
SDL_GL_SetAttribute     dq 0
SDL_GL_SwapBuffers      dq 0

glClear                             dq 0
glBindProgramARB                    dq 0
glNamedProgramStringEXT             dq 0
glNamedBufferDataEXT                dq 0
glGetNamedBufferParameterui64vNV    dq 0
glMakeNamedBufferResidentNV         dq 0
glEnable                            dq 0
glEnableClientState                 dq 0
glVertexAttribFormatNV              dq 0
glEnableVertexAttribArray           dq 0
glBufferAddressRangeNV              dq 0
glDrawArrays                        dq 0
glPathCommandsNV                    dq 0
glStencilFillPathNV                 dq 0
glCoverFillPathNV                   dq 0
glStencilFunc                       dq 0
glStencilOp                         dq 0

segment readable

g_Path:
.NAME = 1
align 1
.Cmds db GL_MOVE_TO_NV,GL_LINE_TO_NV,GL_LINE_TO_NV,GL_LINE_TO_NV,GL_LINE_TO_NV,GL_LINE_TO_NV,GL_LINE_TO_NV,GL_CLOSE_PATH_NV
.CMDS_COUNT = $ - .Cmds
align 4
.Coords dd -0.5,-0.5, 0.5,-0.5, 0.5,0.5, 0.3,0.5, 0.3,-0.3, -0.3,-0.3, -0.3,0.3
.COORDS_COUNT = ($ - .Coords) / 4
.COORDS_TYPE = GL_FLOAT

g_FP:
.NAME = 1
align 1
.Src:
db '!!NVfp4.0',10
db 'PARAM c = { 0,1,0,1 };'
db 'MOV result.color,c;'
db 'END',0
.SRC_SIZE = $ - .Src - 1

align 1

g_str_libSDL db 'libSDL-1.2.so.0',0

g_str_SDL_Init          db 'SDL_Init',0
g_str_SDL_Quit          db 'SDL_Quit',0
g_str_SDL_SetVideoMode  db 'SDL_SetVideoMode',0
g_str_SDL_PollEvent     db 'SDL_PollEvent',0
g_str_SDL_GetTicks      db 'SDL_GetTicks',0

g_str_SDL_GL_LoadLibrary    db 'SDL_GL_LoadLibrary',0
g_str_SDL_GL_GetProcAddress db 'SDL_GL_GetProcAddress',0
g_str_SDL_GL_SetAttribute   db 'SDL_GL_SetAttribute',0
g_str_SDL_GL_SwapBuffers    db 'SDL_GL_SwapBuffers',0

g_str_glClear                               db 'glClear',0
g_str_glBindProgramARB                      db 'glBindProgramARB',0
g_str_glNamedProgramStringEXT               db 'glNamedProgramStringEXT',0
g_str_glNamedBufferDataEXT                  db 'glNamedBufferDataEXT',0
g_str_glGetNamedBufferParameterui64vNV      db 'glGetNamedBufferParameterui64vNV',0
g_str_glMakeNamedBufferResidentNV           db 'glMakeNamedBufferResidentNV',0
g_str_glEnable                              db 'glEnable',0
g_str_glEnableClientState                   db 'glEnableClientState',0
g_str_glVertexAttribFormatNV                db 'glVertexAttribFormatNV',0
g_str_glEnableVertexAttribArray             db 'glEnableVertexAttribArray',0
g_str_glBufferAddressRangeNV                db 'glBufferAddressRangeNV',0
g_str_glDrawArrays                          db 'glDrawArrays',0
g_str_glPathCommandsNV                      db 'glPathCommandsNV',0
g_str_glStencilFillPathNV                   db 'glStencilFillPathNV',0
g_str_glCoverFillPathNV                     db 'glCoverFillPathNV',0
g_str_glStencilFunc                         db 'glStencilFunc',0
g_str_glStencilOp                           db 'glStencilOp',0
